package net.apps.std;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;

import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.border.LineBorder;

import net.apps.core.ApplContext;
import net.apps.core.Channel;
import net.apps.core.ChannelListener;
import net.apps.core.Message;
import net.apps.core.StdAppl;
import net.apps.std.EditTextProtos;
import net.apps.std.TextMessageProtocol.TextMessage;
import net.apps.std.spi.RemoteInputControl;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.im.InputContext;
import java.util.Locale;

/**
 * Provides actions from keyboard or similar hardware
 * 
 * @author Maxim Kizub
 * 
 */

public class TextEditor implements StdAppl, WindowListener, ChannelListener {

	private final ApplContext context;
	private final TextFrame frame;

	public TextEditor(ApplContext context) {
		this.context = context;
		this.frame = new TextFrame();
		this.frame.addWindowListener(this);
	}
	
	@Override
	public void onStart() {
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				frame.pack();
				frame.setLocationByPlatform(true);
				frame.setVisible(true);
			}
		});
		Channel channel = context.getConnection().getChannel(0);
		channel.setChannelListener(this);
//		Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
//			@Override
//			public void eventDispatched(AWTEvent event) {
//				System.out.println("InputEvent: "+event);
//			}
//		}, AWTEvent.INPUT_METHOD_EVENT_MASK);
	}

	@Override
	public void onStop() {
		Channel channel = context.getConnection().getChannel(0);
		channel.setChannelListener(null);
	}

	@Override
	public void onWakeup() {
	}

	@Override
	public void onChannelEvent(Channel channel) {
		do {
			Message msg = channel.take(0);
			if (msg == null)
				return;
			if (msg instanceof TextMessage) {
				final TextMessage tmsg = (TextMessage)msg;
				javax.swing.SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						Object im = frame.getInputContext().getInputMethodControlObject();
						if (im instanceof RemoteInputControl) {
							processMessageByInputMethod(tmsg, (RemoteInputControl) im);
						} else {
							// processMessageByFrame(gen);
						}
					}
				});
			}
		} while (channel.peek() != null);
	}
	
	private void processMessageByInputMethod(TextMessage tmsg, RemoteInputControl im) {
		try {
			putText(tmsg.text, im);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void processMessageByFrame(TextMessage tmsg) {
		try {
			putText(tmsg.text);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void moveTo(EditTextProtos.MoveTo to, RemoteInputControl im) {
	}
	private void moveTo(EditTextProtos.MoveTo to) {
		try {
			JTextField f = frame.tfield;
			switch (to) {
			case HOME:
				f.setCaretPosition(0);
				break;
			case PREV:
				if (f.getCaretPosition() > 0)
					f.setCaretPosition(f.getCaretPosition()-1);
				break;
			case NEXT:
				if (f.getCaretPosition() < f.getText().length())
					f.setCaretPosition(f.getCaretPosition()+1);
				break;
			case END:
				f.setCaretPosition(f.getText().length());
				break;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void insMode(EditTextProtos.InsMode ins, RemoteInputControl im) {
		
	}
	private void insMode(EditTextProtos.InsMode ins) {
		switch (ins) {
		case INSERT:
			frame.with_replace = false;
			break;
		case REPLACE:
			frame.with_replace = true;
			break;
		}
	}

	private void putText(String text, RemoteInputControl im) {
		im.putRemoteText(text);
	}
	
	private void putText(String text) {
		JTextField f = frame.tfield;
		if (f.getSelectionStart() < f.getSelectionEnd()) {
			// we have selected text to replase
			f.replaceSelection(text);
		} else {
			if (frame.with_replace)
				f.moveCaretPosition(f.getCaretPosition()+text.length());
			f.replaceSelection(text);
		}
		//f.setCaretPosition(f.getCaretPosition()+text.length());
	}

	@Override
	public void windowOpened(WindowEvent e) {
	}

	@Override
	public void windowClosing(WindowEvent e) {
		context.getApplManager().requestFinish(this);
	}

	@Override
	public void windowClosed(WindowEvent e) {
		context.getApplManager().requestFinish(this);
	}

	@Override
	public void windowIconified(WindowEvent e) {
	}

	@Override
	public void windowDeiconified(WindowEvent e) {
	}

	@Override
	public void windowActivated(WindowEvent e) {
	}

	@Override
	public void windowDeactivated(WindowEvent e) {
	}


	@SuppressWarnings("serial")
	private class TextFrame extends JFrame {
		private JTextField tfield;
		private boolean with_replace;
		private Locale old_locale;
		public TextFrame() {
			super("Text Receiver");
			JPanel panel = new JPanel();
			panel.setLayout(new BorderLayout());
			panel.setFocusable(true);
			
			tfield = new JTextField();
			tfield.setHorizontalAlignment(JLabel.CENTER);
			tfield.getActionMap().put("remote", new AbstractAction() {
				@Override public void actionPerformed(ActionEvent e) {
					InputContext ictx = getInputContext();
					if (old_locale != null) {
						ictx.selectInputMethod(Locale.getDefault());
						tfield.setBorder(null);
						old_locale = null;
					} else {
						Locale ictx_locale = ictx.getLocale();
						ictx.selectInputMethod(new Locale("remote"));
						old_locale = ictx_locale;
						Object im = ictx.getInputMethodControlObject();
						if (im instanceof RemoteInputControl) {
							tfield.setBorder(new LineBorder(Color.GREEN, 4));
						} else {
							tfield.setBorder(new LineBorder(Color.RED, 4));
						}
					}
				}
			});
			tfield.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_R, KeyEvent.CTRL_DOWN_MASK), "remote");

			panel.add(tfield, BorderLayout.CENTER);

			setPreferredSize(new Dimension(300, 100));
			getContentPane().add(panel);
			
			//enableInputMethods(true);
			//tfield.enableInputMethods(true);
		}
	}

}
